Update table pages to scroll full page#93877
Conversation
265dd82 to
e3d26d7
Compare
|
@Krishna2323 Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button] |
|
🚧 @shawnborton has triggered a test Expensify/App build. You can view the workflow run here. |
|
🧪🧪 Use the links below to test this adhoc build on Android, iOS, and Web. Happy testing! 🧪🧪
|
|
Otherwise feeling pretty good to me, very excited for this one! |
trjExpensify
left a comment
There was a problem hiding this comment.
Looks nice, good from product. 👍
|
@Krishna2323 One scope question: |
|
I would say yes, as we want all tables to behave the same. |
…ing-flow # Conflicts: # src/components/Table/TableBody.tsx # src/pages/DynamicReportParticipantsPage.tsx
…ing-flow # Conflicts: # src/components/Tables/AgentsTable/index.tsx # src/components/Tables/WorkspaceRoomsTable/index.tsx
|
@Krishna2323 @shawnborton Following up on the scope question — done ✅
All checks are green and the branch has no conflicts. Ready for review 🙌 |
|
Awesome, let's get this into final review @Krishna2323 |
Monosnap.screencast.2026-07-15.08-41-30.mp4 |
|
@Krishna2323 This happened because the merge-conflict resolution removed the FlashList initialization guard, allowing sticky headers to access LayoutManager before the first layout. |
|
conflicts |
|
working on it |
|
Now working on solving new conflicts :) |
|
Done! |
|
@codex review |
| </HeaderWithBackButton> | ||
| {shouldDisplayButtonsInSeparateLine && !!getHeaderButtons() && <View style={[styles.pl5, styles.pr5]}>{getHeaderButtons()}</View>} | ||
|
|
||
| {(!hasVisibleCategories || isLoading) && headerContent} |
There was a problem hiding this comment.
While loading, headerContent renders outside the table; once data exists it becomes headerComponent (line 702). They aren’t double-mounted at once, but the subtitle relocates when load finishes.
Can we always pass it through the table (headerComponent={headerContent}) so it doesn’t jump? Same pattern on Tags/Taxes.
There was a problem hiding this comment.
This transition is intentional for now. The table is not mounted while loading, and always passing headerComponent would duplicate the header in the loaded-empty state unless we also rework that fallback. I’d prefer to keep the existing loading/empty composition in this PR.
| {!shouldDisplayButtonsInSeparateLine && getHeaderButtons()} | ||
| </HeaderWithBackButton> | ||
| {shouldDisplayButtonsInSeparateLine && !!getHeaderButtons() && <View style={[styles.pl5, styles.pr5]}>{getHeaderButtons()}</View>} | ||
| {(!hasVisibleTags || isLoading) && headerContent} |
There was a problem hiding this comment.
Same as Categories: subtitle outside while loading/empty (here), then headerComponent inside once tags are visible (line 888). Prefer one table-owned path so it doesn’t relocate.
There was a problem hiding this comment.
Same here — this is intentional for the current loading/empty fallback. Passing the subtitle into the table alone would duplicate it when loaded with no tags, so I’d keep the existing composition in this PR.
| {!shouldDisplayButtonsInSeparateLine && headerButtons} | ||
| </HeaderWithBackButton> | ||
| {shouldDisplayButtonsInSeparateLine && !!headerButtons && <View style={[styles.pl5, styles.pr5]}>{headerButtons}</View>} | ||
| {(!hasVisibleTaxes || isLoading) && headerContent} |
There was a problem hiding this comment.
Same load transition as Categories/Tags — subtitle outside on load/empty, then moved into headerComponent when taxes are visible (line 420). Please use a single path through the table.
There was a problem hiding this comment.
Same for Taxes — this is intentional for the current loading/empty fallback. Passing the subtitle into the table alone would duplicate it when loaded with no taxes, so I’d keep the existing composition in this PR.
|
Codex Review: Didn't find any major issues. Swish! Reviewed commit: ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
…ing-flow # Conflicts: # src/components/Table/Table.tsx


Explanation of Change
Adds
headerComponentsupport to the sharedTableso page-level controls (header content, buttons, search/filter bar) render inside the table'sFlashListand scroll away with the rows, while the table column header is rendered as a sticky list item. Row render indexes andscrollToIndexcallers remain aligned to the real table data, and sticky-header activation waits until the list has data to avoid the StickyHeaders load-time error.All migrated table pages now use the table-owned header flow: Workspaces, Domains (list, admins, groups, members), Categories, Tags, Taxes, Members, Company Cards, Distance Rates, Per Diem, Rooms, Rules (personal rules and all workspace rules tabs), Agents, Expensify Cards, and report participants.
The table empty states (
Table.EmptyState/Table.NoResultsState) render inside the scrolling list below the page header, so the page controls stay visible and usable when the table is empty or a search/filter matches nothing.This PR also $ #95556: on native, focusing the table search bar now scrolls it above the keyboard (using the existing
useScrollToFocusedInputpattern), so the input stays visible while typing in landscape.Fixed Issues
$ #92930
PROPOSAL: #92930 (comment)
$ #95556
Tests
Offline tests
QA Steps
Same as tests.
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectionAvatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: Native
611393262-bb275b7b-db8e-4386-b9f5-19de01001916.mp4
Android: mWeb Chrome
611381825-6fceb35a-5f11-4439-97cd-76fac7124bd9.mp4
iOS: Native
Screen.Recording.2026-06-23.at.12.49.39.AM.mov
iOS: mWeb Safari
VIDEO-2026-06-23-00-03-34.mp4
MacOS: Chrome / Safari
ezyZip.53.mp4